package com.ssy.lingxi.component.redis.serviceImpl;

import com.ssy.lingxi.component.redis.config.RedisModeDetector;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.*;

/**
 * RedisStringUtils实现类(用于存储字符串类型数据, 存储之前不会进行序列化)
 * @author jw.chen
 * @date 2020-08-01
 */
@Repository("redisStringUtils")
public class RedisStringUtilsImpl implements IRedisStringUtils {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisModeDetector detector;

    static Long size = 0L;

    /**
     * 保存数据
     *
     * @param key      key值
     * @param value    value值
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean set(String key, String value, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.set(key, value);
        });
    }

    /**
     * 保存数据并设置超时时间
     *
     * @param key      key值
     * @param value    value值
     * @param expire   超时时间，单位 秒
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean set(String key, String value, Long expire, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            stringCon.set(key, value);
            if (expire != null && expire > 0) {
                stringCon.expire(key, expire);
            }
            return true;
        });
    }

    /**
     * 获取key对应的值
     *
     * @param key      key值
     * @param db_index redis数据库下标
     * @return 获取结果
     */
    @Override
    public String get(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<String>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.get(key);
        });
    }

    /**
     * 删除指定的key
     *
     * @param key      key值
     * @param db_index redis数据库下标
     */
    @Override
    public Long del(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.del(key);
        });
    }

    /**
     * 删除以keyPrex为前缀的数据
     *
     * @param keyPrex  key值
     * @param db_index redis数据库下标
     */
    @Override
    public Long delByPrex(String keyPrex, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            Collection<String> keys = stringCon.keys(keyPrex + "*");
            if (!keys.isEmpty()) {
                return stringCon.del(keys.toArray(new String[0]));
            }
            return null;
        });
    }

    /**
     * 删除指定的key
     *
     * @param keys     keys值
     * @param db_index redis数据库下标
     */
    @Override
    public Long del(List<String> keys, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            String[] redis_keys = keys.toArray(new String[0]);
            return stringCon.del(redis_keys);
        });
    }

    /**
     * 以秒为单位，返回给定key的剩余生存时间
     *
     * @param key      key值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Long ttl(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.ttl(key);
        });
    }

    /**
     * 判断key是否存在
     *
     * @param key      key值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Boolean exists(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.exists(key);
        });
    }

    /**
     * 判断存在多少个key
     *
     * @param keys     keys值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Long exists(List<String> keys, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            String[] redis_keys = keys.toArray(new String[0]);
            return stringCon.exists(redis_keys);
        });
    }

    /**
     * 查找所有符合给定模式 pattern 的 key
     *
     * @param key KEYS * 匹配数据库中所有 key 。
     *            KEYS h?llo 匹配 hello ， hallo 和 hxllo 等。
     *            KEYS h*llo 匹配 hllo 和 heeeeello 等。
     *            KEYS h[ae]llo 匹配 hello 和 hallo ，但不匹配 hillo
     * @return 查询结果
     */
    @Override
    public List<String> searchKey(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<List<String>>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            Collection<String> redis_values = stringCon.keys(key);
            if (redis_values.size() > 0) {
                return new ArrayList<>(redis_values);
            } else {
                return null;
            }
        });
    }

    /**
     * 查找所有符合给定模式 pattern 的 key
     *
     * @param keyList KEYS * 匹配数据库中所有 key 。
     *            KEYS h?llo 匹配 hello ， hallo 和 hxllo 等。
     *            KEYS h*llo 匹配 hllo 和 heeeeello 等。
     *            KEYS h[ae]llo 匹配 hello 和 hallo ，但不匹配 hillo
     * @return 查询结果
     */
    @Override
    public List<Object> searchKeyList(List<String> keyList, Integer db_index) {
        return stringRedisTemplate.executePipelined((RedisCallback<Object>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            keyList.forEach(stringCon::keys);
            return null;
        });
    }

    /**
     * 查找所有符合给定模式 pattern 的 key
     *
     * @param key scan match * 匹配数据库中所有 key 。
     * @return 查询结果
     */
    @Override
    public Set<String> scanKey(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> binaryKeys = new HashSet<>();

            Cursor<byte[]> cursor = connection
                    .scan(new ScanOptions.ScanOptionsBuilder().match(key).count(1000).build());
            while (cursor.hasNext()) {
                binaryKeys.add(new String(cursor.next()));
            }
            return binaryKeys;
        });
    }

    /**
     * 查找所有符合给定模式pattern的key的个数
     *
     * @param key KEYS * 匹配数据库中所有 key 。
     *            KEYS h?llo 匹配 hello ， hallo 和 hxllo 等。
     *            KEYS h*llo 匹配 hllo 和 heeeeello 等。
     *            KEYS h[ae]llo 匹配 hello 和 hallo ，但不匹配 hillo
     * @return 查询结果
     */
    @Override
    public int size(String key, Integer db_index) {
        List<String> result = this.searchKey(key, db_index);
        if (result != null && !result.isEmpty()) {
            return result.size();
        }
        return 0;
    }

    /**
     * 递增1
     *
     * @param key      key值
     * @param db_index redis数据库下标
     */
    @Override
    public Long increment(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.incr(key);
        });
    }

    /**
     * 递增1
     *
     * @param key      key值
     * @param db_index redis数据库下标
     * @param seconds  超时秒数
     */
    @Override
    public Long increment(String key, Integer db_index, long seconds) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            Long incr = stringCon.incr(key);
            stringCon.expire(key, seconds);
            return incr;
        });
    }

    /**
     * 递增
     *
     * @param key      key值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Long increment(String key, long data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.incrBy(key, data);
        });
    }

    /**
     * 递增
     *
     * @param key      key值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Double increment(String key, double data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Double>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.incrBy(key, data);
        });
    }

    /**
     * 递减1
     *
     * @param key      key值
     * @param db_index redis数据库下标
     */
    @Override
    public Long decrement(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.decr(key);
        });
    }

    /**
     * 递减
     *
     * @param key      key值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Long decrement(String key, long data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.decrBy(key, data);
        });
    }

    /**
     * 保存数据
     *
     * @param key      key值
     * @param field    field值
     * @param value    value值
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean hSet(String key, String field, String value, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hSet(key, field, value);
        });
    }

    /**
     * 保存数据并设置超时时间
     *
     * @param key      key值
     * @param field    field值
     * @param value    value值
     * @param expire   超时时间，单位 秒
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean hSet(String key, String field, String value, Long expire, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            stringCon.hSet(key, field, value);
            if (expire != null && expire > 0) {
                stringCon.expire(key, expire);
            }
            return true;
        });
    }

    /**
     * 获取key对应的值
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public String hGet(String key, String field, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<String>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hGet(key, field);
        });
    }

    /**
     * 保存数据
     *
     * @param key      key值
     * @param value    value值
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean hMSet(String key, Map<String, String> value, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            stringCon.hMSet(key, value);
            return true;
        });
    }

    /**
     * 批量设置
     *
     * @param keyValueList key和value值集合
     * @param db_index     redis数据库下标
     */
    @Override
    public void hMSetBatch(List<HashMap<String, Map<String, String>>> keyValueList, Integer db_index) {
        stringRedisTemplate.executePipelined((RedisCallback<Object>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            keyValueList.forEach(keyField -> {
                for (Map.Entry<String, Map<String, String>> entry : keyField.entrySet()) {
                    String key = entry.getKey();
                    Map<String, String> value = entry.getValue();
                    stringCon.hMSet(key, value);
                }
            });
            return null;
        });
    }

    /**
     * 批量设置
     *
     * @param keyValueMap key和value值集合
     * @param db_index    redis数据库下标
     */
    @Override
    public void hMSetBatch(HashMap<String, Map<String, String>> keyValueMap, Integer db_index) {
        stringRedisTemplate.executePipelined((RedisCallback<Object>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            for (Map.Entry<String, Map<String, String>> entry : keyValueMap.entrySet()) {
                String key = entry.getKey();
                Map<String, String> value = entry.getValue();
                stringCon.hMSet(key, value);
            }
            return null;
        });
    }

    /**
     * 保存数据并设置超时时间
     *
     * @param key      key值
     * @param value    value值
     * @param expire   超时时间，单位 秒
     * @param db_index redis数据库下标
     * @return 保存结果
     */
    @Override
    public Boolean hMSet(String key, Map<String, String> value, Long expire, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            stringCon.hMSet(key, value);
            if (expire != null && expire > 0) {
                stringCon.expire(key, expire);
            }
            return true;
        });
    }

    /**
     * 获取key对应的值
     *
     * @param key      key值
     * @param fields   fields值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public List<String> hMGet(String key, String[] fields, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<List<String>>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hMGet(key, fields);
        });
    }

    /**
     * 获取key对应的值
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public String hMGet(String key, String field, Integer db_index) {
        List<String> valueList = this.hMGet(key, new String[]{field}, db_index);
        if (valueList != null && !valueList.isEmpty()) {
            return valueList.get(0);
        } else {
            return null;
        }
    }

    /**
     * 获取key对应的值
     *
     * @param keyFieldList key和field值集合
     * @param db_index     redis数据库下标
     * @return 查询结果
     */
    @Override
    public List<Object> hMGetBatch(List<HashMap<String, String[]>> keyFieldList, Integer db_index) {
        return stringRedisTemplate.executePipelined((RedisCallback<Object>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            keyFieldList.forEach(keyField -> {
                for (Map.Entry<String, String[]> entry : keyField.entrySet()) {
                    String key = entry.getKey();
                    String[] fields = entry.getValue();
                    stringCon.hMGet(key, fields);
                }
            });
            return null;
        });
    }

    /**
     * 获取key对应的值
     *
     * @param keyFieldMap key和field值集合
     * @param db_index     redis数据库下标
     * @return 查询结果
     */
    @Override
    public List<Object> hMGetBatch(HashMap<String, String[]> keyFieldMap, Integer db_index) {
        return stringRedisTemplate.executePipelined((RedisCallback<Object>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            for (Map.Entry<String, String[]> entry : keyFieldMap.entrySet()) {
                String key = entry.getKey();
                String[] fields = entry.getValue();
                stringCon.hMGet(key, fields);
            }
            return null;
        });
    }

    /**
     * 获取key对应的值
     *
     * @param key      key值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Map<String, String> hGetAll(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Map<String, String>>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hGetAll(key);
        });
    }

    /**
     * 删除指定的key
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hDel(String key, String field, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hDel(key, field);
        });
    }

    /**
     * 删除指定的key
     *
     * @param key      key值
     * @param fields   keys值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hDel(String key, List<String> fields, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            String[] redis_keys = fields.toArray(new String[0]);
            return stringCon.hDel(key, redis_keys);
        });
    }

    /**
     * 判断key是否存在
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Boolean hExists(String key, String field, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Boolean>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hExists(key, field);
        });
    }

    /**
     * 判断存在多少个key
     *
     * @param key      key值
     * @param fields   keys值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public Long hExists(String key, List<String> fields, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            fields.forEach(field -> {
                Boolean exists = stringCon.hExists(key, field);
                if (exists) {
                    size++;
                }
            });
            return size;
        });
    }

    /**
     * 查找所有符合给定模式pattern的key中的所有field
     *
     * @param key Key值
     * @param db_index redis数据库下标
     * @return 查询结果
     */
    @Override
    public List<String> searchHKey(String key, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<List<String>>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            Set<String> redis_fields = stringCon.hKeys(key);
            if (redis_fields.size() > 0) {
                return new ArrayList<>(redis_fields);
            } else {
                return null;
            }
        });
    }

    /**
     * 查找所有符合给定模式pattern的key中的所有field的个数
     *
     * @param key Key值
     * @return 查询结果
     */
    @Override
    public int hSize(String key, Integer db_index) {
        List<String> result = this.searchHKey(key, db_index);
        if (result != null && !result.isEmpty()) {
            return result.size();
        }
        return 0;
    }

    /**
     * 递增1
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hIncrement(String key, String field, Integer db_index) {
        return this.hIncrement(key, field, 1, db_index);
    }

    /**
     * 递增
     *
     * @param key      key值
     * @param field    field值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hIncrement(String key, String field, long data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hIncrBy(key, field, data);
        });
    }

    /**
     * 递增
     *
     * @param key      key值
     * @param field    field值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Double hIncrement(String key, String field, double data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Double>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hIncrBy(key, field, data);
        });
    }

    /**
     * 递减1
     *
     * @param key      key值
     * @param field    field值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hDecrement(String key, String field, Integer db_index) {
        return this.hDecrement(key, field, 1, db_index);
    }

    /**
     * 递减
     *
     * @param key      key值
     * @param field    field值
     * @param data     累加值
     * @param db_index redis数据库下标
     */
    @Override
    public Long hDecrement(String key, String field, long data, Integer db_index) {
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> {
            StringRedisConnection stringCon = (StringRedisConnection) con;
            con.select(detector.isCluster() ? 0 : db_index == null ? 0 : db_index);
            return stringCon.hIncrBy(key, field, -data);
        });
    }


    /**
     * 根据key 和起始和结束下标获取 zset的数据集合
     *
     * @param key        集合key
     * @param startIndex 开始下标
     * @param endIndex   结束下标
     * @author wrc
     */
    @Override
    public Set<String> getZSet(String key, Integer startIndex, Integer endIndex) {
        return stringRedisTemplate.opsForZSet().range(key, startIndex, endIndex);
    }
    /**
     * 根据key获取 zset的数据集合大小
     *
     * @param key        集合key
     * @author wrc
     */
    @Override
    public Long getZSetSize(String key) {
        return stringRedisTemplate.opsForZSet().size(key);
    }

    /**
     * 根据key 和 起始和结束下标获取 zset的数据集合
     * 并且返回分数
     *
     * @param key        集合key
     * @param startIndex 开始下标
     * @param endIndex   结束下标
     * @author wrc
     */
    @Override
    public  Map<String,Double> rangeWithScores(String key, Integer startIndex, Integer endIndex) {
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().rangeWithScores(key, startIndex, endIndex);
        Map<String,Double> hashMap=new HashMap<>();
        if(typedTuples == null) {
            return new HashMap<>();
        }

        typedTuples.forEach(map->{
            hashMap.put(map.getValue(),map.getScore());
        });
        return hashMap;
    }

    /**
     * 根据key 和 起始和结束下标获取 zset的数据集合[根据score顺序]
     * 并且返回分数
     *
     * @param key        集合key
     * @param startIndex 开始下标
     * @param endIndex   结束下标
     * @author wrc
     */
    @Override
    public  List<Map<String,Double>> rangeWithScoresOrderByScore(String key, Integer startIndex, Integer endIndex) {
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().rangeWithScores(key, startIndex, endIndex);
        List<Map<String,Double>> list=new ArrayList<>();
        if(typedTuples == null) {
            return new ArrayList<>();
        }

        typedTuples.forEach(map->{
            HashMap<String,Double> hashMap = new HashMap<>();
            hashMap.put(map.getValue(),map.getScore());
            list.add(hashMap);

        });
        return list;
    }

    /**
     * 根据key 和 起始和结束下标获取 zset的Key集合[根据score顺序]
     *
     * @param key        集合key
     * @param startIndex 开始下标
     * @param endIndex   结束下标
     * @author wrc
     */
    @Override
    public  List<String> rangeKeysOrderByScore(String key, Integer startIndex, Integer endIndex) {
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().rangeWithScores(key, startIndex, endIndex);
        List<String> list = new ArrayList<>();
        if(typedTuples == null) {
            return new ArrayList<>();
        }
        typedTuples.forEach(map-> list.add(map.getValue()));
        return list;
    }

    /**
     * 单个添加元素到zset中去
     *
     * @param key   key
     * @param value 元素值
     * @param score 排序分数
     * @return 是否添加成功
     */
    @Override
    public Boolean addZSet(String key, String value, Double score) {
        return stringRedisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * 单个删除zset中的元素
     *
     * @param key   key
     * @param value 元素值
     * @return 是否添加成功
     */
    @Override
    public Long removeZSet(String key,String value) {
        return stringRedisTemplate.opsForZSet().remove(key, value);
    }

    /**
     * 批量添加元素到zset中去
     * @author wrc
     * @date 2021/4/29
     */
    @Override
    public Long batchAddZSet(String key, Map<String, Double> map) {
        Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();
        map.keySet().forEach(str -> {
            DefaultTypedTuple<String> tuple = new DefaultTypedTuple<>(str, map.get(str));
            tuples.add(tuple);
        });
        return stringRedisTemplate.opsForZSet().add(key, tuples);
    }

    /**
     * 根据key获取zset中元素的排名
     */
    @Override
    public Long findZSet(String key, String value) {
        return stringRedisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 根据key获取zset中元素的分数
     * @param key  Key值
     * @param value Value值
     */
    @Override
    public Double score(String key, String value) {
        return stringRedisTemplate.opsForZSet().score(key, value);
    }

    private static final RedisScript<String> quantity_incr = new DefaultRedisScript<>("if(redis.call('exists', KEYS[1]) == 1) then if (tonumber(redis.call('get',KEYS[1])) < tonumber(ARGV[1])) then return tostring(redis.call('incr', KEYS[1])) else return '-1' end else return tostring(redis.call('incr', KEYS[1])) end", String.class);

    @Override
    public String getCouponQuantityScript(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public  String executeCouponQuantityScript(String key, Integer quantity) {
        return stringRedisTemplate.execute(quantity_incr,
                stringRedisTemplate.getStringSerializer(),
                stringRedisTemplate.getStringSerializer(),
                Collections.singletonList(key), String.valueOf(quantity));
    }
}
